home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 145
/
Gekkan Dennou Club - 2000.6 Vol. 145 (Japan).7z
/
Gekkan Dennou Club - 2000.6 Vol. 145 (Japan) (Track 1).bin
/
tools
/
sharp
/
sxwork3.lzh
/
サンプル応用編
/
簡易ドロー
/
SDRAW.C
< prev
next >
Wrap
Text File
|
1994-03-10
|
38KB
|
1,317 lines
/******************************************************************************
* sdraw.c: ドロー編集の処理関数
******************************************************************************
* Workroom SX-68K Sample Program Copyright 1994 SHARP
*/
#include <stdio.h>
#include <string.h>
#include <sxmemory.h> /* メモリマンを利用するときに必要 */
#include <event.h> /* イベントマンを利用するときに必要 */
#include <sxgraph.h> /* グラフ系マネージャを利用するときに必要 */
#include <dialog.h> /* ダイアログマンを利用するときに必要 */
#include "sdraw.h" /* このプログラム固有のヘッダファイル */
/******************************************************************************
* drawAll(): ウィンドウ内部全体の描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void drawAll(ComVal *pcv)
{
/* dataを元に描画されたすべての図形の描画を行う */
drawNext(pcv, pcv->data);
/* アクティブ図形にハンドルを表示する */
if (pcv->actData != NULL)
/* 図形の移動または拡大/縮小時以外のときハンドルを表示する */
if (!(pcv->drawType == 8 && pcv->selMode != -1))
dispHdlRect(pcv, (*pcv->actData)->id);
}
/******************************************************************************
* drawNext(): 現在描画されている図形をすべて描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* ComData **hcd 描画図形のデータハンドル
*/
void drawNext(ComVal *pcv, ComData **hcd)
{
/* 一番最初に描画された図形データから描画を行う */
/* 指定図形データのハンドルがNULLならば処理終了 */
if (hcd == NULL)
return;
/* 1つ前のデータのハンドルを渡して図形の描画を行う */
drawNext(pcv, (*hcd)->next);
/* 移動または拡大処理中でかつ指定のハンドルが選択図形のときの処理 */
if (pcv->drawType == 8 && pcv->selMode != -1 && pcv->actData == hcd)
return;
/* 実際のデータの描画を行う */
drawOne(pcv, hcd);
}
/******************************************************************************
* drawOne(): 指定された図形データの描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* ComData **hcd 描画図形のデータハンドル
*/
void drawOne(ComVal *pcv, ComData **hcd)
{
ComData **temp;
/* 指定図形データのペンサイズに設定する */
GMPenSize((*hcd)->penSize.x_y);
/* 指定図形データの描画色に設定する */
GMForeColor((*hcd)->color);
/* 図形の種類が多角形ではないとき */
if ((*hcd)->id >= 1 && (*hcd)->id <= 4)
/* 図形の種類および描画モードによって描画を行う */
drawZukei(pcv, (*hcd)->id, (*hcd)->drawMode, &(*hcd)->bounds);
/* 多角形のとき */
else {
temp = pcv->actData;
pcv->actData = hcd;
/* 描画モードによって多角形の描画を行う */
drawZukei(pcv, 8, (*hcd)->drawMode, &(*hcd)->bounds);
pcv->actData = temp;
}
}
/******************************************************************************
* setInpRgnPos(): 多角形処理中のマウスレフトダウンイベント処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void setInpRgnPos(ComVal *pcv)
{
Point pt;
/* メインウィンドウをカレントグラフにする */
GMSetGraph(&pcv->windowPtr->graph);
/* 入力座標をローカル座標系に変換する */
pt.x_y = GMGlobalToLocal(pcv->event.ev.where.x_y);
/* 取得座標が画面を外れてないかチェックする */
checkPos(pcv, &pt);
/* downPosに入力座標を設定 */
pcv->downPos = pt;
if (pcv->rgnCnt == 0) {
pcv->rbSize.l.l_t = pt.x_y;
pcv->rbSize.l.r_b = pt.x_y;
}
/* 入力がダブルクリックかどうかをチェックする */
if (checkDClick(pcv))
/* ダブルクリックのときリージョン終了 */
/* pcv->animFlagを2にする */
pcv->animFlag = 2;
/* リージョンの描画を行う */
drawGraph(pcv);
}
/******************************************************************************
* setComData(): 登録時の共通データの設定
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* ComData **hcd 登録の共通データポインタ
* 注釈:
* 図形登録時の共通データ部分の設定を行う。
* また、データを登録したハンドルの確保を行う。
*/
void setComData(ComVal *pcv, ComData **hcd)
{
ComData **temp;
/* 図形種別の設定 */
(*hcd)->id = pcv->drawType;
/* 描画色の設定 */
(*hcd)->color = pcv->paletFC;
/* 描画ペンサイズの設定 */
(*hcd)->penSize = pcv->penSize;
/* 描画モードの設定 */
(*hcd)->drawMode = pcv->drawMode;
/* データを登録したハンドルの確保を行う */
/* データが1件も登録されていないとき */
if (pcv->dataCnt == 0 && pcv->data == NULL) {
(*hcd)->next = NULL;
pcv->data = hcd;
/* すでに登録されたデータが存在するとき */
} else {
temp = pcv->data;
pcv->data = hcd;
(*hcd)->next = temp;
}
/* 登録データ数を更新する */
pcv->dataCnt++;
/* ハンドルを消去する */
if (pcv->actData != NULL)
dispHdlRect(pcv, (*pcv->actData)->id);
/* カレント図形のハンドルを設定する */
pcv->actData = pcv->data;
/* カレント図形の表示を行う */
if ((*hcd)->id >= 1 && (*hcd)->id <= 4)
/* 図形の描画を行う */
drawZukei(pcv, pcv->drawType, pcv->drawMode, &(*hcd)->bounds);
else {
/* 入力された多角形の描画を行う */
drawZukei(pcv, 8, pcv->drawMode, &(*hcd)->bounds);
/* リージョン処理フラグをオフにする */
pcv->rgnCnt = 0;
}
/* 描画フラグをクリアする */
pcv->animFlag = 0;
/* カレント図形のハンドルの設定および表示を行う */
dispCurHdl(pcv);
}
/******************************************************************************
* dispCurHdl(): カレント図形のハンドルの設定および表示
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void dispCurHdl(ComVal *pcv)
{
int i;
Rect rc, rch;
ComData **hcd = pcv->actData;
rc = (*hcd)->bounds;
if ((*hcd)->id == 1) {
pcv->rcHandle[0].d.left = rc.d.left - 2;
pcv->rcHandle[0].d.top = rc.d.top - 2;
pcv->rcHandle[0].d.right = rc.d.left + 2;
pcv->rcHandle[0].d.bottom = rc.d.top + 2;
pcv->rcHandle[1].d.left = rc.d.right - 2;
pcv->rcHandle[1].d.top = rc.d.bottom - 2;
pcv->rcHandle[1].d.right = rc.d.right + 2;
pcv->rcHandle[1].d.bottom = rc.d.bottom + 2;
/* ハンドルを描画する */
dispHdlRect(pcv, (*hcd)->id);
return;
}
for (i = 0; i < 8; i++) {
rch = pcv->rcHandle[i];
if (i >= 0 && i <= 2) {
rch.d.top = rc.d.top - 2;
rch.d.bottom = rc.d.top + 2;
}
if (i >= 5 && i <= 7) {
rch.d.top = rc.d.bottom - 2;
rch.d.bottom = rc.d.bottom + 2;
}
if (i == 0 || i == 3 || i == 5) {
rch.d.left = rc.d.left - 2;
rch.d.right = rc.d.left + 2;
}
if (i == 2 || i == 4 || i == 7) {
rch.d.left = rc.d.right - 2;
rch.d.right = rc.d.right + 2;
}
if (i == 1 || i == 6) {
rch.d.left = rc.d.left + (rc.d.right - rc.d.left) / 2;
rch.d.right = rch.d.left + 2;
if (rc.d.right % 2 == 0)
rch.d.left -= 2;
}
if (i == 3 || i == 4) {
rch.d.top = rc.d.top + (rc.d.bottom - rc.d.top) / 2;
rch.d.bottom = rch.d.top + 2;
if (rc.d.bottom % 2 == 0)
rch.d.top -= 2;
}
pcv->rcHandle[i] = rch;
}
/* ハンドルを描画する */
dispHdlRect(pcv, (*hcd)->id);
}
/******************************************************************************
* dispHdlRect(): カレント図形のハンドルを表示
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* int type 処理している図形の種類
*/
void dispHdlRect(ComVal *pcv, int type)
{
int i, max;
int savPenMode;
if (pcv->actData == NULL) /* アクティブ図形が存在しないか? */
return;
/* メインウィンドウをカレントグラフにする */
GMSetGraph(&pcv->windowPtr->graph);
savPenMode = GMPenMode(G_XOR); /* ペンモードをXORにする */
max = (type == 1) ? 2 : 8;
for (i = 0; i < max; i++)
GMFillRect(&pcv->rcHandle[i]);
GMPenMode(savPenMode); /* ペンモードを元に戻す */
}
/******************************************************************************
* checkRectPos(): レクタングルの座標チェックおよび調整
******************************************************************************
* 引数: Rect *prc レクタングルへのポインタ
* 注釈:
* レクタングルの各座標をpt1がレクタングルの左上角に、pt2がレクタングルの
* 右下角の座標になるように調整を行う。
*/
void checkRectPos(Rect *prc)
{
short save;
/* topがbottomより大きいときは入れ換える */
if (prc->d.top > prc->d.bottom) {
save = prc->d.top;
prc->d.top = prc->d.bottom;
prc->d.bottom = save;
}
/* leftがrightより大きいときは入れ換える */
if (prc->d.left > prc->d.right) {
save = prc->d.left;
prc->d.left = prc->d.right;
prc->d.right = save;
}
}
/******************************************************************************
* checkPos(): 指定座標が親ウィンドウの画面内にあるかを判断する処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* Point *ppt チェック座標(ローカル座標系)へのポインタ
* 注釈:
* 指定のチェック座標が親ウィンドウの画面から外れてるときは、画面内の最大
* 座標と置き換える。
*/
void checkPos(ComVal *pcv, Point *ppt)
{
int calcF = 0;
BOOLEAN flag = FALSE, flag2 = FALSE;
double a, b;
Point calcP, calcP2;
/* 処理図形が直線のとき */
if (pcv->drawType == 1 || pcv->drawType == 5) {
calcP = *ppt;
/* 座標が画面のどこを指しているのかをチェックする */
if (ppt->p.x < 0) {
/* 指定座標のX座標が負の値のとき */
calcP.p.x = 0;
flag = TRUE;
} else if (ppt->p.x > WIN_H) {
/* 指定座標のX座標が画面の右端より大きいとき */
calcP.p.x = WIN_H;
flag = TRUE;
}
if (ppt->p.y < 0) {
/* 指定座標のY座標が負の値のとき */
calcP.p.y = 0;
flag2 = TRUE;
} else if (ppt->p.y > WIN_V) {
/* 指定座標のY座標が画面の底辺の値より大きいとき */
calcP.p.y = WIN_V;
flag2 = TRUE;
}
if (flag)
/* X切片を計算するとき */
calcF += 1;
if (flag2)
/* Y切片を計算するとき */
calcF += 2;
if (calcF == 3)
/* XY両切片を求めるときcalcPをcalcP2にも設定する */
calcP2 = calcP;
if (calcF == 0)
/* 画面上に指定の座標は存在するので処理終了 */
return;
if (pcv->downPos.p.x == calcP.p.x || pcv->downPos.p.y == calcP.p.y) {
/* 画面の境界に前回入力値が存在するとき */
*ppt = calcP;
return;
}
if (pcv->downPos.p.x == ppt->p.x) {
/* 傾きがないとき */
ppt->p.y = calcP.p.y;
return;
}
/* 方程式y = ax + bの要素aおよびbを求める */
a = (double)(pcv->downPos.p.y - ppt->p.y) / (double)(pcv->downPos.p.x - ppt->p.x);
b = (double) pcv->downPos.p.y - a * (double) pcv->downPos.p.x;
/* calcFにより切片を求める */
if (calcF != 2)
/* X切片を求めるとき */
calcP.p.y = (short)(a * (double) calcP.p.x + b);
if (calcF != 1)
/* Y切片を求めるとき */
calcP.p.x = (short)(((double) calcP.p.y - b) / a);
if (calcF == 3) {
/* XY両切片を求めるとき */
calcP2.p.x = (short)(((double) calcP2.p.y - b) / a);
if (!(calcP.p.x >= 0 && calcP.p.x <= WIN_H)
&& !(calcP.p.y >= 0 && calcP.p.y <= WIN_H))
/* 画面の内側に存在する座標をcalcPに設定する */
calcP = calcP2;
}
/* 算出した座標をpptに設定する */
*ppt = calcP;
return;
} else {
/* 処理図形が 長方形,面取り長方形,楕円のとき */
if (ppt->p.x < 0)
/* 指定座標のX座標が負の値のとき */
ppt->p.x = 0;
else if (ppt->p.x > WIN_H)
/* 指定座標のX座標が画面の右端より大きいとき */
ppt->p.x = WIN_H;
if (ppt->p.y < 0)
/* 指定座標のY座標が負の値のとき */
ppt->p.y = 0;
else if (ppt->p.y > WIN_V)
/* 指定座標のY座標が画面の底辺の値より大きいとき */
ppt->p.y = WIN_V;
}
}
/******************************************************************************
* drawGraphRgn(): ウィンドウ内部の多角形の描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* 注釈: drawTypeが多角形のときの処理を行う。
*/
void drawGraphRgn(ComVal *pcv)
{
int cnt = pcv->rgnCnt;
/* 多角形の座標入力点数が0のとき */
if (cnt == 0) {
/* 始点をセーブする */
pcv->rgnDPoint[cnt].x = (double) pcv->downPos.p.x;
pcv->rgnDPoint[cnt].y = (double) pcv->downPos.p.y;
/* ラバーバンド表示のために始点座標を設定する */
pcv->rbSize.l.l_t = pcv->downPos.x_y;
/* カウントアップ */
pcv->rgnCnt++;
/* ダブルクリックされたとき */
} else if (pcv->animFlag == 2)
/* 多角形の登録処理を行う */
makeRgn(pcv);
else {
/* 入力された点を設定する */
pcv->rgnDPoint[cnt].x = (double) pcv->downPos.p.x;
pcv->rgnDPoint[cnt].y = (double) pcv->downPos.p.y;
pcv->rgnCnt++;
/* 入力された部分の仮表示を行う */
pcv->rbSize.l.r_b = pcv->downPos.x_y;
pcv->dispRbFlag = TRUE;
dispRubberBand(pcv, 1);
/* 次のラバーバンド表示のために始点座標を設定する */
pcv->rbSize.l.l_t = pcv->downPos.x_y;
/* 入力可能な最終点のとき、ダブルクリックされたものと見なす */
if (cnt == 99) {
DMError(D_CONFIRM, "これ以上の点は入力できません。\r"
"多角形を終了します。");
/* 多角形の登録処理を行う */
makeRgn(pcv);
}
}
}
/******************************************************************************
* makeRgn(): リージョン図形の登録および描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void makeRgn(ComVal *pcv)
{
int cnt, errCode;
short dx, dy;
LPoint lpt;
ComData **hcd;
/* 多角形の仮表示の消去を行う */
dispRubberBand(pcv, 2);
GMPenSize(pcv->penSize.x_y); /* ペンサイズを設定する */
GMForeColor(pcv->paletFC);
/* データ登録用にメモリを確保する */
hcd = MMChHdlNew(sizeof(ComData));
if (hcd == NULL) {
DMError(D_CONFIRM, "メモリが不足しています。\r"
"データの登録ができません。");
return;
}
/* 空のリージョンを作成する */
(*hcd)->ext.rgn.hdl = GMNewRgn();
if ((*hcd)->ext.rgn.hdl == NULL) {
DMError(D_CONFIRM, "メモリが確保できません。");
return;
}
/* リージョンの記録開始 */
GMOpenRgn();
/* 多角形の描画 */
/* 表示位置をデータの先頭に設定する */
lpt = LONGWORD(pcv->rgnDPoint[0].x, pcv->rgnDPoint[0].y);
GMMove(lpt);
/* データを元に描画を行う */
for (cnt = 1; cnt < pcv->rgnCnt; cnt++)
GMLine(LONGWORD(pcv->rgnDPoint[cnt].x, pcv->rgnDPoint[cnt].y));
/* 始点データと結ぶ */
GMLine(lpt);
/* リージョンの記録終了 */
errCode = GMCloseRgn((*hcd)->ext.rgn.hdl);
if (errCode < 0) {
DMError(D_CONFIRM, "メモリが不足しています。\r"
"リージョンの記録ができません。");
return;
}
/* 多角形を囲むレクタングルの座標をcomDataのboundsに設定する */
(*hcd)->bounds = (*(*hcd)->ext.rgn.hdl)->bounds;
/* 多角形の点数を設定 */
(*hcd)->ext.rgn.cnt = pcv->rgnCnt;
/* リージョンデータを設定する */
memcpy((*hcd)->ext.rgn.dPoint, pcv->rgnDPoint, sizeof(DPoint) * MAX_RGN_CNT);
/* boundsの左上座標からの相対座標に変換する */
dx = (*hcd)->bounds.d.left;
dy = (*hcd)->bounds.d.top;
for (cnt = 0; cnt < pcv->rgnCnt; cnt++) {
(*hcd)->ext.rgn.dPoint[cnt].x -= dx;
(*hcd)->ext.rgn.dPoint[cnt].y -= dy;
}
/* 共通データの登録処理 */
setComData(pcv, hcd);
}
/******************************************************************************
* dispRubberBand(): ラバーバンド表示処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* int mode 描画方法
* = 0: 通常のラバーバンド表示
* = 1: ラバーバンド表示の消去のみ
* = 2: リージョンの仮表示消去
* 注釈: 処理図形のラバーバンド表示を行う。
*/
void dispRubberBand(ComVal *pcv, int mode)
{
int cnt, type;
int disp;
int savPenMode;
Point pt;
Rect savRect;
/* 処理対象外 */
if (mode == 0) {
if (pcv->drawType == 5) {
if (pcv->rgnCnt == 0)
return;
} else if (pcv->animFlag != 1 || !EMLStill())
return;
}
/* 選択処理のとき */
if (pcv->drawType == 8) {
/* 現在選択されているデータが存在しないとき、または
図形選択モードのときは、何もせずに終了 */
if (pcv->actData == NULL || pcv->selMode == -1)
return;
/* ペンサイズを設定する */
GMPenSize((*pcv->actData)->penSize.x_y);
} else
GMPenSize(pcv->penSize.x_y); /* ペンサイズを設定する */
GMForeColor(G_BLACK); /* フォアグラウンドカラーを黒にする */
savPenMode = GMPenMode(G_XOR); /* ペンモードをXORにする */
/* 通常のラバーバンド処理のとき */
if (mode == 0) {
/* マウスポインタの位置を取得する */
pt.x_y = EMMSLoc();
/* 取得座標が画面を外れてないかチェックする */
checkPos(pcv, &pt);
/* 前回の位置と変わってるとき */
if (!(pcv->dispRbFlag && pt.p.x == pcv->rbPos.p.x && pt.p.y == pcv->rbPos.p.y)) {
/* 画面上にラバーバンド表示がある場合は消去する */
if (pcv->dispRbFlag) {
/* drawZukeiの第2パラメータを設定する */
disp = pcv->drawType;
if (disp == 8) {
disp = (*pcv->actData)->id;
if (disp == 5)
disp = 9;
}
/* 表示されているラバーバンドの消去 */
drawZukei(pcv, disp, 0, &pcv->rbSize);
/* ラバーバンド表示フラグをFALSEにする */
pcv->dispRbFlag = FALSE;
}
/* rbSizeのデータをセーブする */
savRect = pcv->rbSize;
/* ラバーバンド座標の設定を行う */
type = setRBRect(pcv, pt.x_y);
/* 多角形のとき */
if (type == 0) {
if (pcv->drawType == 8) {
/* 拡大/縮小処理のとき */
if (pcv->selMode > 0) {
if (!GMEmptyRect(&pcv->rbSize)) {
/* 拡大/縮小後の多角形
の各点を求める */
double dx, dy, sx, sy, a, b;
sx = (double)(savRect.d.right - savRect.d.left);
sy = (double)(savRect.d.bottom - savRect.d.top);
dx = (double)(pcv->rbSize.d.right - pcv->rbSize.d.left);
dy = (double)(pcv->rbSize.d.bottom - pcv->rbSize.d.top);
for (cnt = 0; cnt < pcv->rgnCnt; cnt++) {
a = pcv->rgnDPoint[cnt].x;
b = pcv->rgnDPoint[cnt].y;
pcv->rgnDPoint[cnt].x = dx * a / sx;
pcv->rgnDPoint[cnt].y = dy * b / sy;
}
} else
/* rbSizeのデータを元に戻す */
pcv->rbSize = savRect;
}
disp = 9;
} else
disp = 5;
/* ラバーバンドの表示を行う */
drawZukei(pcv, disp, 0, &pcv->rbSize);
/* ラバーバンド表示フラグをTRUEにする */
pcv->dispRbFlag = TRUE;
} else if (type > 0) {
/* ラバーバンドの表示を行う */
drawZukei(pcv, type, 0, &pcv->rbSize);
/* ラバーバンド表示フラグをTRUEにする */
pcv->dispRbFlag = TRUE;
}
/* 入力点を格納しておく */
pcv->rbPos = pt;
}
/* ラバーバンド消去のとき */
} else if (mode == 1) {
if (pcv->dispRbFlag) {
/* drawZukeiの第2パラメータを設定する */
disp = pcv->drawType;
if (disp == 8) {
disp = (*pcv->actData)->id;
if (disp == 5)
disp = 9;
}
/* 表示されているラバーバンドの消去 */
drawZukei(pcv, disp, 0, &pcv->rbSize);
/* ラバーバンド表示フラグをFALSEにする */
pcv->dispRbFlag = FALSE;
}
/* 多角形の仮表示消去のとき */
} else {
/* 表示位置をデータの先頭に設定する */
GMMove(LONGWORD(pcv->rgnDPoint[0].x, pcv->rgnDPoint[0].y));
/* 格納データを元に仮表示を消去する */
for (cnt = 1; cnt < pcv->rgnCnt; cnt++)
GMLine(LONGWORD(pcv->rgnDPoint[cnt].x, pcv->rgnDPoint[cnt].y));
}
/* ペンモードを元に戻す */
GMPenMode(savPenMode);
/* 描画色を現在の描画色に設定 */
GMForeColor(pcv->paletFC);
/* ペンサイズを現在の描画色に設定 */
GMPenSize(pcv->penSize.x_y);
}
/******************************************************************************
* drawZukei(): 実際の図形表示処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* int type 描画図形の種類
* int mode 描画モード
= 0: 枠
* = 1: 塗りつぶし
* Rect *prc 表示に使用する座標へのポインタ
* 注釈: 指定の図形を指定の座標を用いて表示する。
*/
void drawZukei(ComVal *pcv, int type, int mode, Rect *prc)
{
int stat;
Rect rc;
ComData **hcd;
switch (type) {
case 1:
case 5:
/* 直線の描画を行う */
GMMove(prc->l.l_t);
GMLine(prc->l.r_b);
break;
case 2: /* 長方形 */
case 3: /* 楕円 */
case 4: /* 面取り長方形 */
/* prcのデータをrcにコピーする */
rc = *prc;
/* レクタングルの座標をチェックする */
checkRectPos(&rc);
if (!GMEmptyRect(&rc)) {
/* null Rectではないとき */
switch (type) {
case 2:
/* 長方形の描画を行う */
if (mode == 0)
/* 描画モードが枠のとき */
GMFrameRect(&rc);
else
/* 描画モードが塗りつぶしのとき */
GMFillRect(&rc);
break;
case 3:
/* 楕円の描画を行う */
if (mode == 0)
/* 描画モードが枠のとき */
GMFrameOval(&rc);
else
/* 描画モードが塗りつぶしのとき */
GMFillOval(&rc);
break;
default:
/* 面取り長方形の描画を行う */
if (mode == 0)
/* 描画モードが枠のとき */
GMFrameRRect(&rc, pcv->radius.x_y);
else
/* 描画モードが塗りつぶしのとき */
GMFillRRect(&rc, pcv->radius.x_y);
break;
}
} else {
/* null Rectのとき */
if (rc.d.right - rc.d.left > rc.d.bottom - rc.d.top) {
rc.d.bottom = rc.d.top;
GMMove(rc.l.l_t);
GMLine(rc.l.r_b);
} else {
rc.d.right = rc.d.left;
GMMove(rc.l.l_t);
GMLine(rc.l.r_b);
}
}
break;
case 8: /* 多角形表示処理 */
hcd = pcv->actData;
if ((*hcd)->ext.rgn.hdl == NULL)
break;
stat = GMEmptyRgn((*hcd)->ext.rgn.hdl);
if (stat == 1) { /* ヌル・リージョンのとき */
rc = (*hcd)->bounds;
if (rc.d.right - rc.d.left > rc.d.bottom - rc.d.top) {
rc.d.bottom = rc.d.top;
GMMove(rc.l.l_t);
GMLine(rc.l.r_b);
} else {
rc.d.right = rc.d.left;
GMMove(rc.l.l_t);
GMLine(rc.l.r_b);
}
(*hcd)->bounds = rc;
break;
}
if (mode == 0)
GMFrameRgn((*hcd)->ext.rgn.hdl);
else
GMFillRgn((*hcd)->ext.rgn.hdl);
break;
case 9: /* 多角形ラバーバンド表示処理 */
dispRBRgn(pcv, 1);
break;
}
}
/******************************************************************************
* dispRBRgn(): 多角形ラバーバンド表示処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* BOOLEAN type 始点と終点の関係
= 0: 2点を結ばない
* = 1: 2点を結ぶ
*/
void dispRBRgn(ComVal *pcv, BOOLEAN type)
{
int cnt;
Point pt;
/* rgnDPoint に格納してあるデータを元に region の仮表示を行う。
このとき格納してあるデータは10倍されているので10分の1にしてから
座標として扱う */
pt.p.x = pcv->rgnDPoint[0].x + pcv->rbSize.d.left;
pt.p.y = pcv->rgnDPoint[0].y + pcv->rbSize.d.top;
GMMove(pt.x_y);
for (cnt = 1; cnt < pcv->rgnCnt; cnt++)
GMLine(LONGWORD((short) pcv->rgnDPoint[cnt].x + pcv->rbSize.d.left, (short) pcv->rgnDPoint[cnt].y + pcv->rbSize.d.top));
if (type == 1)
/* 最終点と始点を結ぶ */
GMLine(pt.x_y);
}
/******************************************************************************
* selectZukei(): 選択処理中のマウスレフトダウンイベント処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* LPoint lpt マウス位置
*/
void selectZukei(ComVal *pcv, LPoint lpt)
{
int num;
ComData **hcd = pcv->actData;
/* メインウィンドウをカレントグラフにする */
GMSetGraph(&pcv->windowPtr->graph);
/* 入力座標がアクティブ図形のハンドルを指しているかの、チェックを行う */
num = checkHdl(pcv, lpt);
if (num != 0) {
/* ハンドルを指しているとき、モードを拡大/縮小処理に設定 */
pcv->selMode = num;
/* ラバーバンドに必要な情報の設定 */
pcv->rbSize = (*hcd)->bounds;
/* 多角形のときは必要なデータをコピーする */
if ((*hcd)->id == 5) {
/* 多角形データをコピーする */
memcpy(pcv->rgnDPoint, (*hcd)->ext.rgn.dPoint, sizeof(DPoint) * MAX_RGN_CNT);
/* 多角形の角数をコピーする */
pcv->rgnCnt = (*hcd)->ext.rgn.cnt;
}
/* 表示されているハンドルを消去する */
if (pcv->actData != NULL)
dispHdlRect(pcv, (*hcd)->id);
/* 現在の選択図形を画面上から消去する */
eraseData(pcv);
pcv->rbPos.x_y = lpt;
return;
}
/* アクティブ図形を指しているとき */
if (checkZukei(hcd, lpt)) {
/* モードを移動に設定 */
pcv->selMode = 0;
/* ラバーバンドに必要な情報の設定 */
pcv->downPos.x_y = lpt;
pcv->rbSize = (*hcd)->bounds;
/* 多角形のときは必要なデータをコピーする */
if ((*hcd)->id == 5) {
/* 多角形データをコピーする */
memcpy(pcv->rgnDPoint, (*hcd)->ext.rgn.dPoint, sizeof(DPoint) * MAX_RGN_CNT);
/* 多角形の角数をコピーする */
pcv->rgnCnt = (*hcd)->ext.rgn.cnt;
}
/* 表示されているハンドルを消去する */
if (pcv->actData != NULL)
dispHdlRect(pcv, (*hcd)->id);
/* 現在の選択図形を画面上から消去する */
eraseData(pcv);
pcv->rbPos.x_y = lpt;
return;
}
/* どの図形を指しているのかをチェックする */
/* hcdに現在の一番上のデータのハンドルを設定する */
hcd = pcv->data;
while (hcd != NULL) {
/* hcdの図形を指しているときはLOOPを抜ける */
if (checkZukei(hcd, lpt))
break;
/* hcdに更に1つ前のデータのハンドルを設定する */
hcd = (*hcd)->next;
}
/* pcv->actData に hcd を設定する。どの図形も指していないときは、
アクティブ図形なしとなり NULL が設定される */
if (pcv->actData != hcd) {
/* 表示されているハンドルを消去する */
if (pcv->actData != NULL)
dispHdlRect(pcv, (*pcv->actData)->id);
/* アクティブ図形を設定する */
pcv->actData = hcd;
/* アクティブ図形にハンドルを表示する */
if (pcv->actData != NULL)
dispCurHdl(pcv);
}
/* モードを選択に設定 */
pcv->selMode = -1;
pcv->rbPos.x_y = lpt;
}
/******************************************************************************
* checkHdl(): ハンドルをクリックしたかのチェック
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* LPoint lpt マウス位置
* 戻り値: int pos ハンドル位置
* = 1~8: 下図参照
* = 0: ハンドル以外の場所をクリック
* 注釈: ハンドルの位置は以下のとおりです。
* 長方形 直線
* 1 2 3 1
* +-------+-------+ +
* | | |
* 4 + + 5 |
* | | |
* +-------+-------+ +
* 6 7 8 2
*/
int checkHdl(ComVal *pcv, LPoint lpt)
{
int pos = 0;
int i, max;
/* アクティブな図形が存在しないときは、処理を終了する */
if (pcv->actData == NULL)
return 0;
/* max値の設定(データが直線/直線以外のとき)*/
max = ((*pcv->actData)->id == 1) ? 2 : 8;
/* ハンドル内をクリックされたかを順にチェックする */
for (i = 0; i < max; i++) {
/* ハンドル内と判断されるとき */
if (GMPtInRect(&pcv->rcHandle[i], lpt)) {
/* pos にハンドル位置を設定する */
pos = i + 1;
break;
}
pos = 0;
}
return pos;
}
/******************************************************************************
* checkZukei(): 指定の図形を選択しているかどうかのチェック
******************************************************************************
* 引数: ComData **hcd 図形データのハンドル
* LPoint lpt マウス位置
* 戻り値: BOOLEAN ret = TRUE: 図形の内側
* = FALSE: 図形の外側
*/
BOOLEAN checkZukei(ComData **hcd, LPoint lpt)
{
BOOLEAN ret = FALSE;
if (hcd == NULL)
return FALSE;
switch ((*hcd)->id) {
case 1: /* 直線 */
ret = checkLine(&(*hcd)->bounds, lpt, &(*hcd)->penSize);
break;
case 2: /* 長方形 */
case 3: /* 楕円 */
case 4: /* 面取り長方形 */
case 5: /* 多角形 */
/* 図形を囲むレクタングル内を選択されたとき */
if (GMPtInRect(&(*hcd)->bounds, lpt))
ret = TRUE;
break;
}
return ret;
}
/******************************************************************************
* checkLine(): 指定の点が指定の線上にあるかどうかの判断
******************************************************************************
* 引数: Rect *prc 線のデータ
* LPoint lpt マウス位置
* Point *pps ペンサイズへのポインタ
* 戻り値: BOOLEAN = TRUE: 線上の点である
* = FALSE: 線上にはない
*/
BOOLEAN checkLine(Rect *prc, LPoint lpt, Point *pps)
{
double a, b, d1 = -1, d2 = -1;
Point pt, pt1, pt2, dpt;
Rect rc;
pt.x_y = lpt;
pt1.x_y = prc->l.l_t;
pt2.x_y = prc->l.r_b;
rc = *prc;
checkRectPos(&rc); /* レクタングルを整える */
dpt.p.x = pt1.p.x - pt2.p.x;
dpt.p.y = pt1.p.y - pt2.p.y;
if (dpt.p.x && dpt.p.y) {
/* 斜めの直線の場合 */
if (pt.p.x < rc.d.left || pt.p.x > rc.d.right)
/* マウス位置が直線の範囲外 */
return FALSE;
/* 方程式 y = ax + bの要素 aおよびb を求める */
a = (double) dpt.p.y / (double) dpt.p.x;
b = (double) pt1.p.y - a * (double) pt1.p.x;
d1 = (double) pt.p.x - ((double) pt.p.y - b) / a + 2;
d2 = (double) pt.p.y - (a * (double) pt.p.x + b) + 2;
} else if (dpt.p.x && !dpt.p.y) {
/* 水平な直線の場合 */
if (pt.p.x < rc.d.left || pt.p.x > rc.d.right)
/* マウス位置が直線の範囲外 */
return FALSE;
d1 = (double) pt.p.y - (double) pt1.p.y + 2;
d2 = -1;
} else if (!dpt.p.x && dpt.p.y) {
/* 垂直な直線の場合 */
if (pt.p.y < rc.d.top || pt.p.y > rc.d.bottom)
/* マウス位置が直線の範囲外 */
return FALSE;
d1 = (double) pt.p.x - (double) pt1.p.x + 2;
d2 = -1;
}
return ((d1 >= 0 && d1 <= pps->p.x + 4)
|| (d2 >= 0 && d2 <= pps->p.y + 4));
}
/******************************************************************************
* setRBRect(): 選択処理中のラバーバンドのレクタングル設定処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* LPoint lpt マウス位置
* 戻り値: int type 1-5: 処理図形の種類
* 0: リージョンのとき
* -1: 対象外
*/
int setRBRect(ComVal *pcv, LPoint lpt)
{
int type, mode;
Point pt, dpt;
ComData **hcd = pcv->actData; /* 選択図形の共通データのハンドル */
/* 処理が選択のとき */
if (pcv->drawType == 8) {
/* modeに処理モードを設定する */
mode = pcv->selMode;
pt.x_y = lpt;
/* 移動モードのとき */
if (mode == 0) {
/* 移動量を求める */
dpt.p.x = pt.p.x - pcv->downPos.p.x;
dpt.p.y = pt.p.y - pcv->downPos.p.y;
/* 移動後のレクタングルを求める */
pcv->rbSize.d.left += dpt.p.x;
pcv->rbSize.d.right += dpt.p.x;
pcv->rbSize.d.top += dpt.p.y;
pcv->rbSize.d.bottom += dpt.p.y;
pcv->downPos = pt;
type = (*hcd)->id;
if (type == 5)
/* 処理図形が多角形のとき0を設定 */
type = 0;
} else if (mode > 0) { /* 拡大/縮小モードのとき */
/* 選択図形が 直線 のとき */
if ((*hcd)->id == 1) {
/* rbSizeの変更を行う */
if (mode == 1)
pcv->rbSize.l.l_t = lpt;
else
pcv->rbSize.l.r_b = lpt;
} else { /* 選択図形が 直線 以外のとき */
/* rbSizeの設定 */
pcv->rbSize = (*hcd)->bounds;
/* rbSizeの left 座標に変更が必要なとき */
if (mode == 1 || mode == 4 || mode == 6)
pcv->rbSize.d.left = pt.p.x;
/* rbSizeの top 座標に変更が必要なとき */
if (mode == 1 || mode == 2 || mode == 3)
pcv->rbSize.d.top = pt.p.y;
/* rbSizeの right 座標に変更が必要なとき */
if (mode == 3 || mode == 5 || mode == 8)
pcv->rbSize.d.right = pt.p.x;
/* rbSizeの bottom 座標に変更が必要なとき */
if (mode == 6 || mode == 7 || mode == 8)
pcv->rbSize.d.bottom = pt.p.y;
checkRectPos(&pcv->rbSize);
}
/* 戻り値の設定 */
type = (*hcd)->id;
if (type == 5)
type = 0;
} else
type = -1;
/* 図形入力処理中 */
} else {
/* ラバーバンド座標の設定を行う */
pcv->rbSize.l.r_b = lpt;
type = pcv->drawType;
}
return type;
}
/******************************************************************************
* decisionZukei(): マウスレフトアップイベント時の図形確定処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void decisionZukei(ComVal *pcv)
{
int type, errCode = 0;
Point pt;
Rect rc;
ComData **hcd;
/* メインウィンドウをカレントグラフにする */
GMSetGraph(&pcv->windowPtr->graph);
/* 入力座標値をグローバルからローカルに変換する */
pt.x_y = GMGlobalToLocal(pcv->event.ev.where.x_y);
/* 座標が画面を外れてないかチェックする */
checkPos(pcv, &pt);
/* 入力座標をupPosに設定 */
pcv->upPos = pt;
/* 処理が選択以外のとき */
if (pcv->drawType != 8) {
/* animFlagを描画に設定 */
pcv->animFlag = 2;
/* 描画処理を行う */
drawGraph(pcv);
}
/* 処理が選択のとき */
/* animFlagをクリアする */
pcv->animFlag = 0;
/* ただの選択処理のときは、何もせずに終了する */
if (pcv->selMode == -1)
return;
/* 画面上にラバーバンド表示がある場合は消去する */
if (pcv->dispRbFlag)
dispRubberBand(pcv, 1);
/* rbSize data save */
rc = pcv->rbSize;
/* ラバーバンド座標の設定を行うことにより確定座標の決定を行う */
type = setRBRect(pcv, pt.x_y);
if (type == 0) {
/* 図形データの共通データのハンドルを hcd に取得する */
hcd = pcv->actData;
/* ヌルレクタングルかどうかをチェックする */
if (!GMEmptyRect(&pcv->rbSize)) {
/* ヌルレクタングルではないとき */
if (pcv->selMode > 0) {
/* 拡大/縮小処理のとき */
int cnt;
double dx, dy, sx, sy;
/* 拡大/縮小後の多角形の各点を求める */
sx = (double)(rc.d.right - rc.d.left);
sy = (double)(rc.d.bottom - rc.d.top);
dx = (double)(pcv->rbSize.d.right - pcv->rbSize.d.left);
dy = (double)(pcv->rbSize.d.bottom - pcv->rbSize.d.top);
for (cnt = 0; cnt < pcv->rgnCnt; cnt++) {
pcv->rgnDPoint[cnt].x = dx * pcv->rgnDPoint[cnt].x / sx;
pcv->rgnDPoint[cnt].y = dy * pcv->rgnDPoint[cnt].y / sy;
}
}
if ((*hcd)->ext.rgn.hdl != NULL) {
/* 多角形のリージョンを作成し直す */
GMOpenRgn();
dispRBRgn(pcv, 1);
errCode = GMCloseRgn((*hcd)->ext.rgn.hdl);
}
if ((*hcd)->ext.rgn.hdl == NULL || errCode < 0) {
DMError(D_CONFIRM, "メモリが不足しています。\r"
"リージョンの記録ができません。");
return;
}
/* 共通データのboundsを再設定する */
(*hcd)->bounds = pcv->rbSize;
/* リージョンデータをコピーする */
memcpy((*hcd)->ext.rgn.dPoint, pcv->rgnDPoint, sizeof(DPoint) * MAX_RGN_CNT);
} else
/* rbSizeデータを元に戻す */
pcv->rbSize = rc;
/* 描画ペンサイズの設定 */
GMPenSize((*pcv->actData)->penSize.x_y);
/* 確定図形の表示を行う */
drawZukei(pcv, 8, (*hcd)->drawMode, &pcv->rbSize);
GMPenSize(pcv->penSize.x_y); /* ペンサイズを設定する */
/* 多角形の角数をセーブする */
pcv->rgnCnt = 0;
} else if (type > 0) {
/* null Rect でかどうかをチェックする */
if (type == 1 || !GMEmptyRect(&pcv->rbSize))
/* null Rectではないとき、または直線のとき、
共通データのboundsを再設定する */
(*pcv->actData)->bounds = pcv->rbSize;
else
/* rbSizeデータを元に戻す */
pcv->rbSize = (*pcv->actData)->bounds;
/* 描画ペンサイズの設定 */
GMPenSize((*pcv->actData)->penSize.x_y);
/* 確定図形の表示を行う */
drawZukei(pcv, type, (*pcv->actData)->drawMode, &pcv->rbSize);
GMPenSize(pcv->penSize.x_y); /* ペンサイズを設定する */
}
/* 選択されているデータのハンドルを表示する */
dispCurHdl(pcv);
pcv->selMode = -1;
}
/******************************************************************************
* deleteData(): 現在指定されている図形の削除
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void deleteData(ComVal *pcv)
{
int savType;
Point pt;
Rect rc;
ComData **hcd, **temp1, **temp2;
if (pcv->actData == NULL)
return;
/* 現在登録されている最後のデータのハンドル */
hcd = pcv->data;
/* 現在選択されているデータのハンドル */
temp1 = pcv->actData;
/* 現在選択されているデータの1つ前のデータのハンドル */
temp2 = (*temp1)->next;
/* 最後に登録された図形と現在選択されている図形が同じとき */
if (hcd == temp1)
pcv->data = temp2;
else {
/* hcdから順にデータをたどっていってnextにtemp1が格納されている
ところを捜し出し、temp2を設定する */
while (hcd != NULL) {
if ((*hcd)->next == temp1) {
(*hcd)->next = temp2;
break;
}
hcd = (*hcd)->next;
}
}
/* 削除するデータを囲むレクタングルをセーブする */
rc = (*temp1)->bounds;
/* 図形の種類とペンサイズをセーブしておく */
savType = (*temp1)->id;
pt = (*temp1)->penSize;
if ((*temp1)->id == 1)
checkRectPos(&rc);
/* ハンドルを消去する */
dispHdlRect(pcv, (*pcv->actData)->id);
/* データカウンタをマイナスする */
pcv->dataCnt--;
if ((*temp1)->id == 5 && (*temp1)->ext.rgn.hdl != NULL)
/* 処理図形が多角形のときは、リージョンハンドルを解放する */
GMDisposeRgn((*temp1)->ext.rgn.hdl);
MMHdlDispose(temp1); /* データ登録用ハンドルを解放する */
/* 選択図形をなしにする */
pcv->actData = NULL;
/* ラインのとき、線幅を考慮する */
if (savType == 1) {
rc.d.right += pt.p.x;
rc.d.bottom += pt.p.y;
}
addUpdate(pcv->windowPtr, &rc); /* 削除データを画面上からも消去する */
}
/******************************************************************************
* eraseData(): 現在の指定図形を画面上から消去
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void eraseData(ComVal *pcv)
{
int savFlag;
Rect rc;
ComData **hcd = pcv->actData;
/* 図形描画のため一時的に描画フラグを0にしておく */
savFlag = pcv->animFlag;
pcv->animFlag = 0;
/* 選択されている図形を囲むレクタングルをグローバル座標系に変換する */
rc = (*hcd)->bounds;
if ((*hcd)->id == 1)
checkRectPos(&rc);
rc.d.left -= 2;
rc.d.top -= 2;
rc.d.right += 2;
rc.d.bottom += 2;
/* 直線のとき、線幅を考慮する */
if ((*hcd)->id == 1) {
rc.d.right += (*hcd)->penSize.p.x;
rc.d.bottom += (*hcd)->penSize.p.y;
checkRectPos(&rc);
}
/* 削除データを画面上からも消去する */
GMClipRect(&rc);
drawGraph(pcv);
GMClipRect(&pcv->windowPtr->graph.rect);
pcv->animFlag = savFlag;
}